#include <OgreOctree.h>
#include <OgreOctreeNode.h>

namespace Ogre
{
	bool Octree::_isTwiceSize(const AxisAlignedBox& box) const
	{
		if (box.isInfinite())
			return false;

		Vector3 halfMBoxSize = mBox.getHalfSize();
		Vector3 boxSize = box.getSize();
		return ((boxSize.x <= halfMBoxSize.x) && (boxSize.y <= halfMBoxSize.y) && (boxSize.z <= halfMBoxSize.z));
	}

	void Octree::_getChildIndex(const AxisAlignedBox& box, int *x, int *y, int *z) const
	{
		Vector3 max = mBox.getMaximum();
		Vector3 min = box.getMinimum();

		Vector3 center = mBox.getMaximum().midPoint(mBox.getMinimum());
		Vector3 ncenter = box.getMaximum().midPoint(box.getMinimum());

		if (ncenter.x > center.x)
			*x = 1;
		else
			*x = 0;

		if (ncenter.y > center.y)
			*y = 1;
		else
			*y = 0;

		if (ncenter.z > center.z)
			*z = 1;
		else
			*z = 0;
	}

	Octree::Octree(Octree* parent)
		: mWireBoundingBox(0),
		  mHalfSize(0, 0, 0)
	{
		for (int i = 0; i < 2; i++)
		{
			for (int j = 0; j < 2; j++)
			{
				for (int k = 0; k < 2; k++)
				{
					mChildren[i][j][k] = 0;
				}
			}
		}

		mParent = parent;
		mNumNodes = 0;
	}

	Octree::~Octree()
	{
		for (int i = 0; i < 2; i++)
		{
			for (int j = 0; j < 2; j++)
			{
				for (int k = 0; k < 2; k++)
				{
					if (mChildren[i][j][k] != 0)
						OGRE_DELETE mChildren[i][j][k];
				}
			}
		}

		if (mWireBoundingBox)
			OGRE_DELETE mWireBoundingBox;

		mParent = 0;
	}

	void Octree::_addNode(OctreeNode* n)
	{
		mNodes.push_back(n);
		n->setOctant(this);

		_ref();
	}

	void Octree::_removeNode(OctreeNode* n)
	{
		mNodes.erase(std::find(mNodes.begin(), mNodes.end(), n));
		n->setOctant(0);

		_unref();
	}

	void Octree::_getCullBounds(AxisAlignedBox* b) const
	{
		b->setExtent(mBox.getMinimum() - mHalfSize, mBox.getMaximum() + mHalfSize);
	}

	WireBoundingBox* Octree::getWireBoundingBox()
	{
		if (mWireBoundingBox == 0)
			mWireBoundingBox = OGRE_NEW WireBoundingBox();

		mWireBoundingBox->setupBoundingBox(mBox);
		return mWireBoundingBox;
	}
}
